package wxapp

import (
	"sync"
	"time"
)

//access_token 的有效期通过返回的 expires_in 来传达，目前是7200秒之内的值，中控服务器需要根据这个有效时间提前去刷新
//在刷新过程中，中控服务器可对外继续输出的老 access_token，此时公众平台后台会保证在5分钟内，新老 access_token 都可用
//设置240秒(<5分钟)刷新一次，确保能够获取有效的access_token
const FLUSH_TOKEN_TM int64 = 240
type WeixinApp struct {
	AppID     	string
	AppSecret 	string
	AccessToken	string
	TokenGetter	TokenGetFunc
	TokenTime	int64
	lock   		sync.Mutex
}

func (app *WeixinApp)getAccessToken() string {
	app.lock.Lock()
	defer app.lock.Unlock()
	tm := time.Now().Unix()
	if tm - app.TokenTime > FLUSH_TOKEN_TM {
		token, err := app.TokenGetter(app.AppID, app.AppSecret)
		if err == nil {
			app.AccessToken = token
			app.TokenTime = tm
		}
	}
	return app.AccessToken
}

//建议使用中控服务器统一获取和刷新 access_token，因此采用自定义逻辑去获取 access_token
type TokenGetFunc func(appid string, secret string) (string, error)
func NewWeixinApp(appid string, secret string, fn TokenGetFunc) *WeixinApp {
	return &WeixinApp{AppID: appid, AppSecret: secret, TokenGetter:fn}
}

//小程序数据解密
func (app *WeixinApp)WxDncrypt(rawData, iv string) (string, error) {
	return WxDncrypt(rawData, app.AppSecret, iv)
}

//根据登录凭证code获取opendid以及session_key
func (app *WeixinApp)GetOpenIdByCode(code string) (WxSessionData, error) {
	return GetOpenIdByCode(app.AppID, app.AppSecret, code)
}

//检查加密信息是否由微信生成（当前只支持手机号加密数据），只能检测最近3天生成的加密数据
func (app *WeixinApp)EncryptedCheck(encrypted_msg_hash string) (EncryptedCheckRet, error) {
	access_token := app.getAccessToken()
	return EncryptedCheck(access_token, encrypted_msg_hash)
}

//用户支付完成后，获取该用户的 UnionId，无需用户授权
func  (app *WeixinApp)GetPaidInfo(param GetPaidInfoReq) (GetPaidInfoRet, error) {
	access_token := app.getAccessToken()
	return GetPaidInfo(access_token, param)
}

//code换取用户手机号
func (app *WeixinApp)GetPhoneNumber(code string) (GetPhoneNumberRet, error) {
	access_token := app.getAccessToken()
	return GetPhoneNumber(access_token, code)
}

//解密用户手机号数据
func (app *WeixinApp)DecodePhoneNumber(rawData, key, iv string) (PhoneInfo, error) {
	return DecodePhoneNumber(rawData, key, iv)
}

//检查一段文本是否含有违法违规内容。
func (app *WeixinApp)CheckText(param CheckTextReq) (CheckTextRet, error) {
	access_token := app.getAccessToken()
	return CheckText(access_token, param)
}

//异步校验图片/音频是否含有违法违规内容。
func (app *WeixinApp)CheckMedia(param CheckMediaReq) (CheckMediaRet, error) {
	access_token := app.getAccessToken()
	return CheckMedia(access_token, param)
}

//发送客服消息给用户
func (app *WeixinApp)SendCustomMessage(param CustomerMessage) error {
	access_token := app.getAccessToken()
	return SendCustomMessage(access_token, param)
}

//发送客服消息给用户：文本消息
func (app *WeixinApp)SendCustomText(touser string, text string) error {
	access_token := app.getAccessToken()
	return SendCustomText(access_token, touser, text)
}

//发送客服消息给用户：图片消息
func (app *WeixinApp)SendCustomImage(touser string, media_id string) error {
	access_token := app.getAccessToken()
	return SendCustomImage(access_token, touser, media_id)
}

//发送客服消息给用户：图文链接
func (app *WeixinApp)SendCustomLink(touser string, title,description,url,thumb_url string) error {
	access_token := app.getAccessToken()
	return SendCustomLink(access_token, touser, title,description,url,thumb_url)
}

//发送客服消息给用户：小程序卡片
func (app *WeixinApp)SendCustomAppPage(touser string, title,pagepath,thumb_media_id string) error {
	access_token := app.getAccessToken()
	return SendCustomAppPage(access_token, touser, title,pagepath,thumb_media_id)
}

//下发客服当前输入状态给用户
func (app *WeixinApp)SendCustomTyping(touser, command string) error {
	access_token := app.getAccessToken()
	return SendCustomTyping(access_token, touser, command)
}

//把媒体文件上传到微信服务器,目前仅支持图片
func (app *WeixinApp)UploadTempMedia(file_path string) (UploadTempMediaRet, error) {
	access_token := app.getAccessToken()
	return UploadTempMedia(access_token, file_path)
}

//获取客服消息内的临时素材。即下载临时的多媒体文件。目前小程序仅支持下载图片文件。
func (app *WeixinApp)GetTempMedia(media_id string) ([]byte, error) {
	access_token := app.getAccessToken()
	return GetTempMedia(access_token, media_id)
}

//发送微信订阅消息
func (app *WeixinApp)SendSubscribeMsg(param SubscribeMsgReq) error {
	access_token := app.getAccessToken()
	return SendSubscribeMsg(access_token, param)
}

//创建被分享动态消息或私密消息的 activity_id，
func (app *WeixinApp)CreateActivity(userid string, is_unionid bool) (CreateActivityRet, error) {
	access_token := app.getAccessToken()
	return CreateActivity(access_token, userid, is_unionid)
}

//修改被分享的动态消息
func (app *WeixinApp)UpdateActivity(param UpdateActivityReq) error {
	access_token := app.getAccessToken()
	return UpdateActivity(access_token, param)
}

//通过该接口生成的小程序码，永久有效，有数量限制
func (app *WeixinApp)CreateACode(param ACodeParam) ([]byte, error) {
	access_token := app.getAccessToken()
	return CreateACode(access_token, param)
}

//通过该接口生成的小程序码，永久有效，数量暂无限制
func (app *WeixinApp)CreateACodeUnlimited(param ACodeParam) ([]byte, error) {
	access_token := app.getAccessToken()
	return CreateACodeUnlimited(access_token, param)
}

//生成页面二维码
func (app *WeixinApp)CreateQCode(page string, width int) ([]byte, error) {
	access_token := app.getAccessToken()
	return CreateQCode(access_token, page, width)
}

//生成小程序shortLink
func (app *WeixinApp)CreateShortLink(param ShortLinkReq) (string, error) {
	access_token := app.getAccessToken()
	return CreateShortLink(access_token, param)
}

//生成临时shortLink
func (app *WeixinApp)CreateShortLinkTemp(page_url string, page_title string) (string, error) {
	access_token := app.getAccessToken()
	return CreateShortLinkTemp(access_token, page_url, page_title)
}

//生成永久shortLink
func (app *WeixinApp)CreateShortLinkPermanent(page_url string, page_title string) (string, error) {
	access_token := app.getAccessToken()
	return CreateShortLinkPermanent(access_token, page_url, page_title)
}

//生成页面Scheme码
func (app *WeixinApp)CreateUrlScheme(param WxUrlSchemeReq) (string, error) {
	access_token := app.getAccessToken()
	return CreateUrlScheme(access_token, param)
}

//查询小程序 scheme 码，及长期有效 quota
func (app *WeixinApp)GetSchemeInfo(scheme string) (SchemeQueryRet, error) {
	access_token := app.getAccessToken()
	return GetSchemeInfo(access_token, scheme)
}

//生成小程序URL Link，
func (app *WeixinApp)CreateUrlLink(param UrlLinkReq) (string, error) {
	access_token := app.getAccessToken()
	return CreateUrlLink(access_token, param)
}

//查询小程序 url_link 配置，及长期有效 quota
func (app *WeixinApp)GetUrlLinkInfo(url_link string) (UrlLinkQueryRet, error) {
	access_token := app.getAccessToken()
	return GetUrlLinkInfo(access_token, url_link)
}

//用于签发 TRTC 和 IM 服务中必须要使用的 UserSig 鉴权票据
func (app *WeixinApp)GenIMUserSig(sdkappid int, key string, identifier string, expire int) (string, error) {
	return GenIMUserSig(sdkappid, key, identifier, expire)
}
